#include "redgui.h"

// A set of tooltips!
GtkTooltips *tooltips;

// Loader
extern "C"
void
load_module ()
{
  addToSystem ("start-gui", dStartGTK);

  addToSystem ("make-about-dialog", make_about_dialog);
  addToSystem ("make-window", make_gtk_window);
  addToSystem ("make-button", make_gtk_button);
  addToSystem ("make-label", make_gtk_label);
  addToSystem ("make-image", make_gtk_image);

  addToSystem ("add-tooltip", add_tooltip);

  addToSystem ("show-widget", show_widget);
  addToSystem ("hide-widget", hide_widget);
  addToSystem ("set-widget-layout", set_widget_layout);
  addToSystem ("make-layout", make_gtk_layout);
  addToSystem ("get-widget-layout", get_widget_layout);
  addToSystem ("add-widget", add_widget);
  dInitGTK ();
}

dGuiObject::dGuiObject ()
{
  type = 'z';
  typeStr = "GUI_OBJECT";
  widget = 0;
  layoutStr = "nil";
  layout = 0;
}

dGuiObject::dGuiObject (GtkWidget *newWidget, string newType)
{
  type = 'z';
  typeStr = newType;
  widget = newWidget;
  layoutStr = "nil";
  layout = 0;
}

dGuiObject::~dGuiObject ()
{
  delete widget;
}

string
dGuiObject::toString ()
{
  return typeStr;
}


// GTK-Related Functions
void
dInitGTK ()
{
  gtk_set_locale ();
  gtk_init (0, 0);
  tooltips = gtk_tooltips_new ();
}

dObject *
dStartGTK (dList *args)
{
  gtk_main ();
  return new dString ("GUI loop finished.");
}

// (add-tooltip widget "tooltip")
dObject *
add_tooltip (dList *args)
{
  if (args == 0 || args->size > 2
      || (*args)[0]->typeStr.substr (0, 3) != "GUI"
      || (*args)[1]->type != 's')
    return new dError ("add-tooltip requires a widget and a string");
  dGuiObject *object = (dGuiObject*)(*args)[0];
  const gchar *tip_text = (*args)[1]->toString ().c_str ();
  gtk_tooltips_set_tip (tooltips, object->widget, tip_text, NULL);
  return T;
}

dObject *
show_widget (dList *args)
{
  if (args == 0 || args->size > 1
      || (*args)[0]->typeStr.substr (0, 3) != "GUI")
    return new dError ("show-widget requires a widget");
  dGuiObject *object = (dGuiObject*)(*args)[0];
  gtk_widget_show_all (object->widget);
  if (object->layoutStr != "nil" && object->layout != 0)
    gtk_widget_show_all (object->layout);
  return T;
}

dObject *
hide_widget (dList *args)
{
  if (args == 0 || args->size > 1
      || (*args)[0]->typeStr.substr (0, 3) != "GUI")
    return new dError ("hide-widget requires a widget");
  dGuiObject *object = (dGuiObject*)(*args)[0];
  gtk_widget_hide_all (object->widget);
  if (object->layoutStr != "nil" && object->layout != 0)
    gtk_widget_hide_all (object->layout);
  return T;
}

// (set-widget-layout widget layout/"layout" etc)
dObject *
set_widget_layout (dList *args)
{
  if (args == 0 || args->size != 2
      || (*args)[0]->typeStr.substr (0, 3) != "GUI"
      || (*args)[1]->type != 's')
    return new dError ("set-widget-layout requires a widget and string argument");
  dGuiObject *object = (dGuiObject*)(*args)[0];
  string layout_type = (*args)[1]->toString ();
  // Replace the existing layout
  if (object->layout != 0)
    {
      delete object->layout;
      object->layout = 0;
    }
  if (layout_type == "hbox")
    {
      object->layoutStr = "HBOX";
      object->layout = gtk_hbox_new (FALSE, 1);
    }
  else if (layout_type == "vbox")
    {
      object->layoutStr = "VBOX";
      object->layout = gtk_vbox_new (FALSE, 1);
    }
  else if (layout_type == "layout")
    {
      object->layoutStr = "LAYOUT";
      object->layout = gtk_layout_new (NULL, NULL);
    }
  else
    {
      object->layoutStr = "nil";
      return nil;
    }
  gtk_container_add (GTK_CONTAINER (object->widget), object->layout);
  return T;
}

// (make-layout "layout" etc)
dObject *
make_gtk_layout (dList *args)
{
  if (args == 0 || args->size != 1
      || (*args)[0]->type != 's')
    return new dError ("make-layout requires a string argument");
  dGuiObject *object;
  string layout_type = (*args)[0]->toString ();
  if (layout_type == "hbox")
    object = new dGuiObject (gtk_hbox_new (FALSE, 1), "GUI_HBOX");
  else if (layout_type == "vbox")
    object = new dGuiObject (gtk_vbox_new (FALSE, 1), "GUI_VBOX");
  else if (layout_type == "layout")
    object = new dGuiObject (gtk_layout_new (NULL, NULL), "GUI_LAYOUT");
  else
    {
      object->layoutStr = "nil";
      return nil;
    }
  object->layoutStr = object->typeStr.substr (4, 20);
  object->layout = object->widget;
  return object;
}

// (get-widget-layout widget)
dObject *
get_widget_layout (dList *args)
{
  if (args == 0 || args->size > 1
      || (*args)[0]->typeStr.substr (0, 3) != "GUI")
    return new dError ("get-widget-layout requires a widget");
  dGuiObject *object = (dGuiObject*)(*args)[0];
  if (object->layoutStr == "nil")
    return nil;
  return new dGuiObject (object->layout, "GUI_" + object->layoutStr);
}

dObject *
add_widget (dList *args)
{
  if (args == 0
      || (*args)[0]->typeStr.substr (0, 3) != "GUI"
      || (*args)[1]->typeStr.substr (0, 3) != "GUI")
    return new dError ("add-widget requires two widgets");
  dGuiObject *parent = (dGuiObject*)(*args)[0];
  if (parent->layoutStr == "nil")
    return nil;
  dGuiObject *child = (dGuiObject*)(*args)[1];
  if (parent->layoutStr == "VBOX" || parent->layoutStr == "HBOX")
    gtk_box_pack_start (GTK_BOX (parent->layout), child->widget, true, true, 2);
  else if (parent->layoutStr == "LAYOUT")
    {
      if ((*args)[2]->type != 'i' || (*args)[3]->type != 'i')
	return nil;
      int x = toInt ((dNumber*)(*args)[2]);
      int y = toInt ((dNumber*)(*args)[3]);
      gtk_layout_put (GTK_LAYOUT (parent->layout), child->widget, x, y);
    }
  return new dGuiObject (parent->layout, "GUI_" + parent->layoutStr);
}


// (gui-about "name" "version" "copyright" "comments" "website")
dObject *
make_about_dialog (dList *args)
{
  GtkAboutDialog *about = (GtkAboutDialog*)gtk_about_dialog_new ();
  gtk_about_dialog_set_name (about, "Application Name");
  gtk_about_dialog_set_version (about, "Version");
  gtk_about_dialog_set_copyright (about, "Copyright");
  gtk_about_dialog_set_comments (about, "Comments\nGo here");
  gtk_about_dialog_set_website (about, "http://a.website.com/");
  return new dGuiObject ((GtkWidget*)about, "GUI_About_Dialog");
}

// (gtk-window "caption" width height)
dObject *
make_gtk_window (dList *args)
{
  if (args == 0)
    return new dError ("make-window requires at least one argument");
  dGuiObject *window = new dGuiObject (gtk_window_new (GTK_WINDOW_TOPLEVEL), "GUI_WINDOW");
  int height = 300;
  int width = 300;
  if ((*args)[0]->type == 's')
    gtk_window_set_title (GTK_WINDOW (window->widget), (*args)[0]->toString ().c_str ());
  else
    return new dError ("make-window's first parameter must be a string");
  if ((*args)[1] != nil)
    {
      if ((*args)[1]->type == 'i')
	width = toInt ((dNumber*)(*args)[1]);
      else
	return new dError ("make-window's second parameter must be an integer");
    }
  debug (args);
  if ((*args)[2] != nil)
    {
      if ((*args)[2]->type == 'i')
	height = toInt ((dNumber*)(*args)[2]);
      else
	return new dError ("make-window's third parameter must be an integer");
    }
  gtk_widget_set_size_request (window->widget, width, height);
  return window;
}


// (make-button "label" width height)
dObject *
make_gtk_button (dList *args)
{
  if (args == 0)
    return new dError ("make-button requires at least one argument");
  dGuiObject *button = new dGuiObject (gtk_button_new (), "GUI_BUTTON");
  int height = 0;
  int width = 0;
  if ((*args)[0]->type == 's')
    gtk_button_set_label (GTK_BUTTON (button->widget), (*args)[0]->toString ().c_str ());
  else if ((*args)[0]->type == 'S')
    {
      gtk_button_set_label (GTK_BUTTON (button->widget), (*args)[0]->toString ().c_str ());
      gtk_button_set_use_stock (GTK_BUTTON (button->widget), TRUE);
    }
  else
    return new dError ("make-button's first parameter must be a string");
  if ((*args)[1] != 0)
    {
      if ((*args)[1]->type == 'i')
	width = toInt ((dNumber*)(*args)[1]);
      else
	return new dError ("make-button's second parameter must be an integer");
    }
  if ((*args)[2] != 0)
    {
      if ((*args)[2]->type == 'i')
	height = toInt ((dNumber*)(*args)[2]);
      else
	return new dError ("make-button's third parameter must be an integer");
    }
  if (height > 0 && width > 0)
    gtk_widget_set_size_request (button->widget, width, height);
  return button;
}


// (make-label "label")
dObject *
make_gtk_label (dList *args)
{
  if (args == 0)
    return new dError ("make-label requires a string");
  dGuiObject *label = new dGuiObject (gtk_label_new (NULL), "GUI_LABEL");
  if ((*args)[0]->type == 's')
    gtk_label_set_text (GTK_LABEL (label->widget), (*args)[0]->toString ().c_str ());
  else
    return new dError ("make-label's only parameter must be a string");
  return label;
}

// (make-image "image")
dObject *
make_gtk_image (dList *args)
{
    if (args == 0)
    return new dError ("make-image requires at least one argument");
  dGuiObject *image = new dGuiObject (0, "GUI_IMAGE");
  int height = 0;
  int width = 0;
  if ((*args)[0]->type == 's')
    image->widget = gtk_image_new_from_file ((*args)[0]->toString ().c_str ());
  else if ((*args)[0]->type == 'S')
    image->widget = gtk_image_new_from_stock ((*args)[0]->toString ().c_str (), GTK_ICON_SIZE_BUTTON);
  else
    return new dError ("make-image's parameter must be a string");
  return image;
}
